home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / x / volume6 / wsxc / part01 next >
Encoding:
Internet Message Format  |  1990-03-20  |  55.9 KB

  1. Path: uunet!cs.utexas.edu!sun-barr!newstop!sun!Central
  2. From: sunpeaks!auto-trol!marbru@Central (Martin Brunecky)
  3. Newsgroups: comp.sources.x
  4. Subject: v06i039: WsXc - Poor man's UIL, Part01/01
  5. Message-ID: <133252@sun.Eng.Sun.COM>
  6. Date: 21 Mar 90 10:29:34 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 1613
  9. Approved: argv@sun.com
  10.  
  11. Submitted-by: sunpeaks!auto-trol!marbru@Central (Martin Brunecky)
  12. Posting-number: Volume 6, Issue 39
  13. Archive-name: wsxc/part01
  14.  
  15.      WsXc - POOR MAN'S UIL
  16.  
  17.      This posting contains WsXc, an Xt Intrinsic  extension  alowing  to
  18.      specify  the  entire  user  interface within X resource database. A
  19.      HelloWorld example using Motif widgets is included.  It is provided
  20.      on  as-is basis, without any support or waranties, to gain feedback
  21.      about this approach of user interface definition.
  22.  
  23.      CONTENTS:
  24.  
  25.      o  README                 Basic description of WsXc facility
  26.  
  27.      This is neither a tutorial, nor a reference manual.For more details
  28.      about individual functions, plese refer to the source - it contains
  29.      detailed  description of each function.  I am sorry I can't provide
  30.      man pages nor Makefile, I just don't know how.
  31.  
  32.      The following files contain the code, based on  R3  Xt  Intrinsics,
  33.      tested  on  SPARC, Ultrix/RISC and VAX/VMS.  I assume compatibility
  34.      with R4, even though it has not been tested.
  35.  
  36.       o  WsCreateXrm.h          defines available public functions
  37.       o  WsCreateXrmFunc.c      widget tree creation and control
  38.       o  WsCvtStrToCallback.c   string to callback resource convertor
  39.  
  40.      The following is a demo application, using the code  listed  above,
  41.      and  Motif  (1.0).   You  can  modify the code to use your favorite
  42.      widget set, and play with application resource files.
  43.  
  44.       o  HelloWorld.c          sample application
  45.       o  HelloWorldBasic       basic X resource file, move to ~/HelloWorld
  46.       o  HelloWorldMore        an expanded X resource file 
  47.  
  48.  
  49. #! /bin/sh
  50. # This is a shell archive.  Remove anything before this line, then unpack
  51. # it by saving it into a file and typing "sh file".  To overwrite existing
  52. # files, type "sh file -c".  You can also feed this as standard input via
  53. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  54. # will see the following message at the end:
  55. #        "End of shell archive."
  56. # Contents:  README WsCreateXrm.h WsCreateXrmFunc.c
  57. #   WsCvtStrToCallback.c HelloWorld.c HelloWorld_Basic HelloWorld_More
  58. # Wrapped by marbru@auto-trol on Fri Mar 16 19:31:21 1990
  59. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  60. if test -f 'README' -a "${1}" != "-c" ; then 
  61.   echo shar: Will not clobber existing file \"'README'\"
  62. else
  63. echo shar: Extracting \"'README'\" \(9584 characters\)
  64. sed "s/^X//" >'README' <<'END_OF_FILE'
  65. X
  66. X    UIL or NOT to UIL ?
  67. X
  68. X    A  few  weeks  ago,  comp.windows.x  carried  a  discussion  of  the
  69. X    advantages and disadvantages of UIL.  Some people suggested that UIL
  70. X    is essentially useless, that the  X  resource  database  is  enough,
  71. X    while  others  have  pointed out that there are things you cannot do
  72. X    with the database alone,  such  as  definition  of  a  widget  tree,
  73. X    callbacks, compound strings etc.
  74. X
  75. X    Prompted by this discussion, I have put together some code which, in
  76. X    my  belief,  extends  the  the X Resource Database so that an ENTIRE
  77. X    USER INTERFACE can be defined (and customized) within the  database.
  78. X    This  avoidins  the  need  for  multiple  sources  of user interface
  79. X    definition by replacing UIL.  I am posting an overview of this "POOR
  80. X    MAN'S  UIL"  here  to  get  some  feedback.
  81. X
  82. X    To start, let me present a simple example of an application-class  X
  83. X    resource file for a Motif based HelloWorld:
  84. X
  85. X    #
  86. X    # shell - an application shell, containing RowColumn organizer
  87. X    #
  88. X    HelloWorld.managed.child_0:             box,xmRowColumn
  89. X    #
  90. X    #  box - the main container, contains label and button
  91. X    #
  92. X    Helloworld.box.spacing:                 8
  93. X    HelloWorld.box.managed.child_0:         label,xmLabel
  94. X    HelloWorld.box.managed.child_1:         button,xmPushButton
  95. X    #
  96. X    #  label
  97. X    #
  98. X    HelloWorld.box.label.labelString:       Hello, WORLD !
  99. X    #
  100. X    #  button
  101. X    #
  102. X    HelloWorld.box.button.labelString:      Push ME
  103. X    HelloWorld.box.button.activateCallback: push(Push again to EXIT)
  104. X    #
  105. X
  106. X    Except for the top-level shell creation, there is NO widget creation
  107. X    code  in  my HelloWorld.  The entire widget tree definition is shown
  108. X    above.  For any widget, I can specify any number  of  children  with
  109. X    all  their  resources, and all recursively.  Callbacks are specified
  110. X    in a similar way, by passing a string argument as call  data.   Note
  111. X    the  example  is  a  starting  point:   It  does  NOT  show  all the
  112. X    functionality such as  deffered  subtree  creation,  manage/unmanage
  113. X    callbacks, etc...
  114. X
  115. X
  116. X    APPLICATION CODE IMPACT
  117. X
  118. X    A runtime interpreter must be able to translate X resource  database
  119. X    strings  into  widget  classes  (or  widget  creation routines), and
  120. X    callbacks.  Even though some systems (VMS for example) allow dynamic
  121. X    binding, the current implementation uses registration routines:
  122. X
  123. X        WsRegisterObjectClass ( app, "xmlabel",      xmLabel           );
  124. X        WsRegisterObjectClass ( app, "xmpushbutton", xmPushButton      );
  125. X        WsRegisterConstructor ( app, "xmRowColumn",  XmCreateRowColumn );
  126. X
  127. X        WsRegisterCallback    ( app, "push",  pushCB, NULL );
  128. X
  129. X    In environments supporting shareable images, all toolkit classes and
  130. X    constructors may be registered during toolkit initialization.
  131. X
  132. X    To initiate creation of the widget tree from the definitions  stored
  133. X    in the X resource database, an application must (either directly, or
  134. X    by means of a callback) invoke the routine:
  135. X
  136. X                      WsCreateXrmChildren ( widget );
  137. X
  138. X
  139. X    WIDGET TREE CREATION MECHANISM
  140. X
  141. X    The WsCreateXrmChildren routine scans the X  resource  database  for
  142. X    widget subresources in the following format:
  143. X
  144. X    path...widget.[un]managed.child_n:    name,class[,nonrecursive]
  145. X
  146. X    For each such subresource, the routine creates a child as  specified
  147. X    by   the   name   and  object  class  (or  the  creation  routine  -
  148. X    constructor).  Creation recursively descends the widget tree, unless
  149. X    stopped  by  a  non-composite  widget/object  or  the "nonrecursive"
  150. X    option.  The latter may be used to defer sub-tree creation, using  a
  151. X    callback    which    invokes   WsCreateXrmChildren   (for   example,
  152. X    WsCreateXrmChildrenCB).
  153. X
  154. X    When a child is created,  WsCreateXrmChildren  checks  the  resource
  155. X    database  for xrmCreateCallback resource for the child, and executes
  156. X    such callbacks if present.  This mechanism allows  the  delivery  of
  157. X    child's  widget  ID  to  other,  already existing widgets (such as a
  158. X    Motif defaultButton resource in dialog boxes).
  159. X
  160. X
  161. X    CALLBACK STRING CONVERSION
  162. X
  163. X    A string to callback converter is provided with  the  package.   The
  164. X    converter  builds an XtCallbackList using registered callback names.
  165. X    Any callback on the list may have an optional  string  argument.   A
  166. X    pointer  to  the  string  is  used  as  callback client data.  If no
  167. X    argument  (string)  is  provided,  the  default  client  data  value
  168. X    provided  at  registration  time  is  used.   The  callback resource
  169. X    specification in the X resource database has the following format:
  170. X
  171. X       path...widget.callbackName:   name[(args)][,name[(args)]]...
  172. X
  173. X    where name is the callback name assigned by WsRegisterCallback,  and
  174. X    args presents an arbitrary string.
  175. X
  176. X
  177. X    WIDGET TREE CONTROL CALLBACKS
  178. X
  179. X    The package provides basic callbacks for widget tree  control.   The
  180. X    callbacks  take  a  (list  of)  widget  names as "client data".  The
  181. X    widget name is qualified according to Xrm  rules:   box.label.   The
  182. X    following is list of the provided callbacks:
  183. X
  184. X     o  CreateXrmChildrenCB ( widgetName, widgetname, ...  )
  185. X        creates children of the named widgets  as  specified  in  the  X
  186. X        resource database
  187. X
  188. X     o  ManageNamedChildrenCB ( widgetName, widgetName, ...  )
  189. X        manages a (list of) named widget(s)
  190. X
  191. X     o  UnmanageNamedChildrenCB ( widgetName, widgetName, ...  )
  192. X        unmanages a (list of) named widget(s).
  193. X
  194. X     o  SetWidgetResourceCB ( resourceName, widgetname, ...  )
  195. X        sets the specified resource in a (list of)  named  widget(s)  to
  196. X        the widget id of the widget invoking the callback.
  197. X
  198. X    Consider the callbacks above as a starting  point.   More  callbacks
  199. X    can  be  provided  to  control  popup/popdown,  to  load  additional
  200. X    resource files and much more.
  201. X
  202. X
  203. X    COMPARISON WITH UIL
  204. X
  205. X    The X resource database user interface definition, here (for lack of
  206. X    better  names)  referred  to  as  WsXc, performs essentialy the same
  207. X    function as UIL.  A complete comparison with UIL  can  not  be  done
  208. X    without  additional  input.   Here  I  try  only  to mention several
  209. X    important differences between UIL and WsXc.
  210. X
  211. X    Implementation:
  212. X    A UIL application uses multiple user  interface  definition  sources
  213. X    (application  code,  UIL  file,  compiled UID file and an X resource
  214. X    file).  WsXc requires only application code and an X resource  file,
  215. X    and  the  application  code  would be limited to callback functions.
  216. X    The UIL approach is based on a compiler generating intermediate code
  217. X    which  is  interpreted  by Mrm at runtime.  WsXc is purely a runtime
  218. X    interpreter.
  219. X
  220. X    Performance:
  221. X    Since UIL uses pre-compiled, machine specific data, the widget  tree
  222. X    creation  could  be  faster  than  that for WsXc.  However, even UIL
  223. X    widget creation accesses the X resource database for  resources  NOT
  224. X    explicitly  specified  by  the  UIL  file.  Since MOST resources are
  225. X    usually NOT explictly specified, the overhead depends  more  on  the
  226. X    Xrm  database  volume,  than  on  the  widget  creation method used.
  227. X    Preliminary experience  with  WsXc  is  favorable.   However,  final
  228. X
  229. X                                                                Page 4
  230. X
  231. X
  232. X    judgement requires much more experience than is currently available.
  233. X
  234. X    Extensibility.
  235. X    Adding new widgets to UIL, even with the new Motif WML facility,  is
  236. X    not an easy process.  Adding new data types (resource representation
  237. X    types) to UIL is sometimes impossible.  On the  contarry,  there  is
  238. X    nothing  special  about adding additional widgets to WsXc.  The same
  239. X    method also applies to adding new data types.  The only  requirement
  240. X    is  the  addition  of  a  convertor from string to a particular data
  241. X    type.
  242. X
  243. X    Syntax Checking:
  244. X    The UIL compiler can perform rigorous  syntax  checking  for  widget
  245. X    resources,  thus  assisting in user interface development.  WsXc can
  246. X    not catch any syntax errors in resource pathname specification, such
  247. X    resources  are  simply  ignored.   However, errors in resource value
  248. X    specification can be caught by the resource converter.  In addition,
  249. X    a  simple tool that acquires a widget's resource list and performs X
  250. X    resource file syntax checking can be provided.
  251. X
  252. X    Value Computations:
  253. X    The UIL compiler can compute  the  geometry  of  individual  widgets
  254. X    using  arbitrary  arithmetic  expressions.  Geometry values in the X
  255. X    resource database can not,  currently,  contain  expressions.   But,
  256. X    since  Xrm  uses  cpp, a string substitution could be applied.  This
  257. X    limitation is a resource converter issue.  A more intelligent string
  258. X    to   integer   converter   could  evaluate  arithmetic  expressions,
  259. X    including X resource database value substitution.  Besides, geometry
  260. X    configuration should be left to the geometry manager widgets and not
  261. X    hardcoded.
  262. X
  263. X    Resource Conversions:
  264. X    UIL supports resource conversions  such  as  colors,  pixelmaps  and
  265. X    compound strings.  Many of the conversions are performed at runtime,
  266. X    using resource converters, the same as WsXc.   For  some  resources,
  267. X    such  as Compound Strings, UIL compile time conversion provides some
  268. X    runtime savings.  In addition, the current string to compound string
  269. X    resource converters are not intelligent enough to allow an unlimited
  270. X    compound string specification in an X resource file.
  271. X
  272. END_OF_FILE
  273. if test 9584 -ne `wc -c <'README'`; then
  274.     echo shar: \"'README'\" unpacked with wrong size!
  275. fi
  276. # end of 'README'
  277. fi
  278. if test -f 'WsCreateXrm.h' -a "${1}" != "-c" ; then 
  279.   echo shar: Will not clobber existing file \"'WsCreateXrm.h'\"
  280. else
  281. echo shar: Extracting \"'WsCreateXrm.h'\" \(1153 characters\)
  282. sed "s/^X//" >'WsCreateXrm.h' <<'END_OF_FILE'
  283. X/*
  284. X*******************************************************************************
  285. X*
  286. X* SCCS_data: %Z%%M% %I%(%G%)
  287. X*
  288. X* Include_name:
  289. X*
  290. X*     WsCreateXrm.h
  291. X*
  292. X* Subsystem_group:
  293. X*
  294. X*     Window System
  295. X*
  296. X* Related_keywords:
  297. X*
  298. X*     Public Defines
  299. X*
  300. X* Include_description:
  301. X*
  302. X*     Public defines for the Window System  widget tree creation from
  303. X*     the Xrm database.
  304. X*
  305. X* Include_history:
  306. X*
  307. X*   mm/dd/yy  initials  action
  308. X*   --------  --------  -------------------------------------------------------
  309. X*   03/02/90   marbru   created
  310. X*
  311. X*******************************************************************************
  312. X*/
  313. X#ifndef _WsCreateXrm_h
  314. X#define _WsCreateXrm_h
  315. X
  316. X
  317. X/* -- Widget constructor registration routine */
  318. X
  319. Xextern void WsRegisterObjectClass ();
  320. Xextern void WsRegisterConstructor ();
  321. Xextern void WsRegisterCallback    ();
  322. Xextern void WsRegisterXrmCallbacks();
  323. X
  324. X/* -- Widget creation routine */
  325. X
  326. Xextern void WsCreateXrmChildren  ();
  327. X
  328. X/* -- Convenience callbacks */
  329. X
  330. Xextern void WsCreateXrmChildrenCB();
  331. Xextern void WsManageNamedChildrenCB();
  332. Xextern void WsUnmanageNamedChildrenCB();
  333. Xextern void WsSetWidgetResourceCB();
  334. X
  335. X#endif  /* _WsCreateXrm_h */
  336. END_OF_FILE
  337. if test 1153 -ne `wc -c <'WsCreateXrm.h'`; then
  338.     echo shar: \"'WsCreateXrm.h'\" unpacked with wrong size!
  339. fi
  340. # end of 'WsCreateXrm.h'
  341. fi
  342. if test -f 'WsCreateXrmFunc.c' -a "${1}" != "-c" ; then 
  343.   echo shar: Will not clobber existing file \"'WsCreateXrmFunc.c'\"
  344. else
  345. echo shar: Extracting \"'WsCreateXrmFunc.c'\" \(22340 characters\)
  346. sed "s/^X//" >'WsCreateXrmFunc.c' <<'END_OF_FILE'
  347. X/*
  348. X*******************************************************************************
  349. X*
  350. X* SCCS_data: %Z%%M% %I%(%G%)
  351. X*
  352. X* Module_name:
  353. X*
  354. X*     WsCreateXrmFunc.c
  355. X*
  356. X* Subsystem_group:
  357. X*
  358. X*     Window System, Widget tree creation from Xrm database
  359. X*
  360. X* Related_keywords: 
  361. X*
  362. X*     Widget, Creation
  363. X*
  364. X* Module_description:
  365. X*
  366. X*     This module contains the functions and convenience callbacks
  367. X*     used to create and manage a widget tree using the Xrm databse.
  368. X*     The Xrm database format used to define widget's children is
  369. X*     as follows:
  370. X*
  371. X*     toplevel...widget.managed.child_n:   name,constructor[,n[onrecursive]]
  372. X*     toplevel...widget.unmanged.child_n:  name,constructor[,n[onrecursive]]
  373. X*
  374. X*     Example:
  375. X*     helloWorld.managed.child_0:             box,XmCreateRowColumn
  376. X*     helloWorld.box.managed.child_0:         label,XmCreateLabel
  377. X*     helloWorld.box.managed.child_1:         button,XmCreatePushButton
  378. X*     helloWorld.box.label.labelString:       Hello, World !
  379. X*     helloWorld.box.button.labelString:      Bye Bye, World !
  380. X*     helloworld.box.button.activateCallback: push(EXIT)
  381. X*
  382. X*     Since (for portability reasons) we can not assume runtime binding,
  383. X*     all widget classes or creation routines (constructors) must be 
  384. X*     "registered"  by the application BEFORE widget tree creation.
  385. X*
  386. X*     The widget tree creation is performed by the WsCreateXrmChildren()
  387. X*     function, which descends the widget tree recursively until no more
  388. X*     children are found, or widget creation is flagged as "nonrecursive",
  389. X*     or a non-composite widget/object is found.
  390. X*
  391. X*     Several convenience callbacks are provided here, more will probbably
  392. X*     follow.
  393. X*
  394. X* Module_interface_summary: 
  395. X*
  396. X*
  397. X*     Xt Widget/Object Class Registration Routine:
  398. X*
  399. X*       WsRegisterObjectClass(
  400. X*        WsAppContext  app,        - application context
  401. X*        String      name,        - class name, case insensitive
  402. X*        WidgetClass   class )   - class record pointer
  403. X*
  404. X*
  405. X*     Xt Widget/Object Contructor Registration Routine:
  406. X*
  407. X*       WsRegisterConstructor(
  408. X*        WsAppContext  app,        - application context
  409. X*        String      name,        - constructor name, case insens.
  410. X*        (*Widget)()   const )   - constructor function pointer
  411. X*
  412. X*
  413. X*     Standard callback registration routine (all the following callbacks)
  414. X*
  415. X*       WsRegisterXrmCallbacks ( 
  416. X*           WsAppContext  app )     - application context
  417. X*
  418. X*     Convenience Callbacks:
  419. X*
  420. X*       WsCreateXrmChildrenCB   ()    - creates children for named widgets
  421. X*       WsManageNamedChildrenCB ()    - manages named widgets
  422. X*       WsUnmanageNamedChidrenCB()    - unmanages named widgets
  423. X*       WsSetWidgetResourceCB   ()    - sets widget resource in named widgets
  424. X*       WsLoadResourceFileCB    ()    - loads a new database file 
  425. X*
  426. X*
  427. X* Module_history:
  428. X*                                                  
  429. X*   mm/dd/yy  initials  function  action
  430. X*   --------  --------  --------  ---------------------------------------------
  431. X*   02/26/90  MarBru    All       Created
  432. X*   02/16/90  MarBru    Create..  Limited creation to composite widgets/objects
  433. X*
  434. X* Design_notes:
  435. X
  436. X*   For VMS, we could have used LIB$FIND_IMAGE_SYMBOL and use dynamic
  437. X*   (runtime) binding. But since most UNIX systems lack such capability,
  438. X*   we stick to the concept of "registration" routines.
  439. X*
  440. X*******************************************************************************
  441. X*/
  442. X/*
  443. X*******************************************************************************
  444. X* Include_files.
  445. X*******************************************************************************
  446. X*/
  447. X
  448. X/*  -- Operating system includes */
  449. X#include <strings.h>
  450. X#include <ctype.h>
  451. X
  452. X/*  -- X Window System includes */
  453. X#include <X11/IntrinsicP.h>
  454. X#include <X11/StringDefs.h>
  455. X
  456. X/*  -- Auto-trol Window System includes */
  457. X
  458. X/*
  459. X*******************************************************************************
  460. X* Private_constant_declarations.
  461. X*******************************************************************************
  462. X*/
  463. X#undef  NUL
  464. X#define NUL '\0'
  465. X#define MAX_XRMSTRING  1024        /* max length of the Xrm DB string  */
  466. X#define MAX_ERRMSG     1024             /* max length of error message        */
  467. X#define MAX_CHILDREN   1024            /* max number of widget's children  */
  468. X#define ADD_CLASSES      16             /* increment of class cache         */
  469. X
  470. X#define WsNxrmCreateCallback "xrmCreateCallback"
  471. X#define WsCXrmCreateCallback "XrmCreateCallback"
  472. X
  473. X/*
  474. X*******************************************************************************
  475. X* Private_type_declarations.
  476. X*******************************************************************************
  477. X    Class/constructor cache record contains both class and constructor,
  478. X    one of which must be NULL.
  479. X*/
  480. Xtypedef struct                /* Class cache record         */
  481. X{
  482. X    XrmQuark       quark;        /* quarkified callback name   */
  483. X    Widget         (*constructor)();    /* constructor function ptr   */
  484. X    WidgetClass    class;               /* widget class pointer       */
  485. X} ClCacheRec;
  486. X
  487. X/*
  488. X*******************************************************************************
  489. X* Private_macro_definitions.
  490. X*******************************************************************************
  491. X*/
  492. X
  493. X/*
  494. X*******************************************************************************
  495. X* Private_data_definitions.
  496. X*******************************************************************************
  497. X    The following cache/registry of known widget classes and contructors, 
  498. X    initially empty, are loaded by the application using "registration" 
  499. X    routines.
  500. X    Assuming small numbers of constructors, the sequential search
  501. X    of such cache is (initially) considered acceptable.
  502. X*/
  503. X
  504. X/*  -- Named object classes cache, intially empty */
  505. X
  506. Xstatic int         classes_num = 0;
  507. Xstatic int         classes_max = 0;
  508. Xstatic ClCacheRec *classes_ptr = NULL;
  509. X
  510. X/*
  511. X*******************************************************************************
  512. X* Private_function_declarations.
  513. X*******************************************************************************
  514. X*/
  515. X
  516. X
  517. X/*
  518. X    -- Names to Widget List
  519. X******************************************************************************
  520. X    This routine converts a string of comma separated widget names
  521. X    (or widget pathes) into a list of widget id's. Blank space ignored
  522. X    If a NULL string is provided, the widget ID of reference widget
  523. X    is put on the list
  524. X    The widget search starts at the TOP of widget hierarchy (using the
  525. X    top level shell as a reference widget), thus the widget pathname
  526. X    must include all the widget parents (excluding the shell).
  527. X*/
  528. Xstatic void NamesToWidgetList ( w, client, widget_list, widget_count )
  529. XWidget        w;            /* reference widget */
  530. Xcaddr_t        client;        /* callback client data - string of names */
  531. XWidget       *widget_list;    /* returned widget list */
  532. XCardinal   *widget_count;    /* returned widget count */
  533. X{
  534. X    char      *string = (String)client;
  535. X    char       name[MAX_XRMSTRING];
  536. X    register char *s;
  537. X    register char *d;
  538. X
  539. X/*  -- default case, no string provided, return the calling widget */    
  540. X    if (!string) 
  541. X    {
  542. X    widget_list[0] = w;
  543. X    *widget_count  = 1;
  544. X    return;
  545. X    }
  546. X
  547. X/*  -- find the reference widget as the toplevel shell */
  548. X    while ( XtParent(w) ) w = XtParent(w);
  549. X
  550. X/*  -- parse the input string "name.name,name.name,name.name.name" */
  551. X    *widget_count = 0;
  552. X    for ( d = name, s = string;  ; s++ )
  553. X    {
  554. X    if ( *s == ',' || *s == NUL )
  555. X    {
  556. X        Widget widget;
  557. X        if ( *s == NUL && d == name ) return;
  558. X        *d = NUL;
  559. X        widget = XtNameToWidget ( w, name );
  560. X        if ( widget )
  561. X        {
  562. X        widget_list[*widget_count] = widget;    
  563. X            (*widget_count)++;
  564. X        }
  565. X        else
  566. X                XtStringConversionWarning (name, "Widget");
  567. X        d = name;
  568. X    }
  569. X    else if ( *s > ' ' )
  570. X    {
  571. X        *d++ = *s;
  572. X    }
  573. X    else
  574. X    ;
  575. X    } 
  576. X}
  577. X/*
  578. X    -- Call Create Callback
  579. X*******************************************************************************
  580. X    This function calls the CreateCallback defined for the widget in Xrm
  581. X    resource database. 
  582. X    Note the  xrmCreateCallback "resource" is NOT a true widget resource,
  583. X    there are no instance data associated with it, and only exists in the
  584. X    Xrm resource database, used ONLY at widget creation time.
  585. X*/
  586. Xstatic Widget CallCreateCallback ( w )
  587. XWidget  w;        /* child's parent */
  588. X{
  589. X    static XtResource res[] =
  590. X    {
  591. X      { WsNxrmCreateCallback, WsCXrmCreateCallback, XtRCallback, 
  592. X        sizeof(XtCallbackList), 0, XtRImmediate, (caddr_t)NULL 
  593. X      },
  594. X    };
  595. X    XtCallbackList  callback = NULL;
  596. X
  597. X    XtGetApplicationResources ( w, &callback, res, XtNumber(res), NULL, 0 );
  598. X
  599. X    /* If there was any callback list defined, invoke all callbacks on list */
  600. X    if ( callback )
  601. X    {
  602. X    XtCallbackRec *cb = callback;
  603. X    for ( cb = callback; cb->callback; cb++ )
  604. X        (*cb->callback) ( w, cb->closure, NULL );
  605. X        
  606. X    }
  607. X}
  608. X
  609. X/*
  610. X    -- Create Database Child
  611. X*******************************************************************************
  612. X    This function checks the resource database for a presence of widget's
  613. X    subresource in a form:
  614. X
  615. X     ...widget.type.child_nn:    name.constr_name[,n[onrecursive]]
  616. X
  617. X    where type is either "managed" or "unmanaged".
  618. X
  619. X    If such a resource is present, the child is created and, if nonrecursive
  620. X    option is NOT present, the CreateDatabseChildren is called for this
  621. X    child causing recursive tree creation. Creation stops if child_0 or
  622. X    two subsequent children are not defined. Creation also stops at any
  623. X    non-composite widget/object. Thus, popup-shells etc. must be created
  624. X    as manager children.
  625. X
  626. X*/
  627. Xstatic Widget CreateDatabaseChild ( w,  nn, type )
  628. XWidget  w;        /* child's parent */
  629. Xint     nn;        /* child # to look for */
  630. XString  type;        /* child type: managed or unmanaged */
  631. X{
  632. X    static XtResource c_resource[] =
  633. X    {
  634. X      { NULL, NULL, XtRString, sizeof(String), 0, XtRImmediate, (caddr_t)NULL },
  635. X    };
  636. X    Boolean   recursive;
  637. X    char      res_name[20];
  638. X    String    string;
  639. X
  640. X    /* update our resource list to look for  type.child_n subresource */
  641. X    sprintf ( res_name, "child_%d", nn );
  642. X    /* toolkit quarkifies resource lists, (flagged by negative offset) */
  643. X    if ( ((int)c_resource[0].resource_offset) < 0 )
  644. X    {
  645. X        XrmQuark qname = XrmStringToQuark(res_name);
  646. X    c_resource[0].resource_name  = (String)qname;
  647. X    c_resource[0].resource_class = (String)qname; /* no class used */
  648. X    }
  649. X    else
  650. X    {
  651. X    c_resource[0].resource_name  = res_name;
  652. X    c_resource[0].resource_class = res_name;  /* no class allowed / used */
  653. X    }
  654. X    XtGetSubresources ( w, &string, type, type, c_resource, 1, NULL, 0 );
  655. X
  656. X    /* Xrm query returned a string for [un]managed.child_n resource, process */
  657. X    if ( string )
  658. X    {
  659. X        void      WsCreateXrmChildren();
  660. X    XrmQuark  quark;
  661. X    Widget   (*found_const)() = NULL;
  662. X    WidgetClass found_class   = NULL;
  663. X    char      name  [MAX_XRMSTRING];
  664. X    char      constr[MAX_XRMSTRING];
  665. X    register  char *s;
  666. X    register  char *d;
  667. X        register  int  i;
  668. X
  669. X    /*  extract widget name */
  670. X    for ( d=name, s=string; (*s && *s!=','); )
  671. X         *d++ = *s++;          
  672. X        *d = NUL;
  673. X
  674. X    /* check for missing class/constructor name */
  675. X    if ( *s != ',' )
  676. X    {
  677. X        char msg [MAX_ERRMSG];
  678. X        sprintf ( msg, 
  679. X               "Resource db error, missing constructor specifier for %s", name );
  680. X        XtWarning( msg );
  681. X        return (Widget)NULL;
  682. X    }
  683. X    s++;
  684. X
  685. X    /* extract class/constructor name and force lowercase, no white space */
  686. X    for ( d=constr; (*s && *s!=','); )
  687. X        if (*s > ' ')
  688. X         *d++ = (isupper(*s)) ? tolower(*s++) : *s++;    
  689. X        else
  690. X          s++;
  691. X        *d = NUL;
  692. X
  693. X    /* check for non-recursive option */
  694. X    recursive = ( *s==',' && (s[1]=='n' || s[1]=='N') ) ? FALSE : TRUE;
  695. X
  696. X    
  697. X    /* try to locate class/constructor in our caches */
  698. X    quark = XrmStringToQuark ( constr );
  699. X    for (i=0; i<classes_num; i++)
  700. X       if ( classes_ptr[i].quark == quark )
  701. X       {
  702. X        found_class = classes_ptr[i].class;
  703. X        found_const = classes_ptr[i].constructor;
  704. X          break;
  705. X       }
  706. X
  707. X    /* if we'w found a class or constructor, create child, call callback */
  708. X    if (found_class || found_const )
  709. X        {
  710. X        Widget child;
  711. X        if ( found_class )
  712. X            child = XtCreateWidget ( name,  found_class, w, NULL, 0 );
  713. X        else
  714. X        child = (*found_const) ( w, name, NULL, 0 );
  715. X
  716. X        CallCreateCallback ( child );
  717. X        if ( recursive ) WsCreateXrmChildren ( child );
  718. X        return (child);
  719. X    }
  720. X    else
  721. X    {
  722. X        char msg[MAX_ERRMSG];
  723. X        sprintf ( msg,"Cannot create child %s using %s, unknown class/constructor",
  724. X              name, constr );
  725. X        XtWarning( msg );
  726. X        return (Widget)NULL;
  727. X    }
  728. X    }
  729. X    else
  730. X    {
  731. X    return (Widget)NULL;
  732. X    }
  733. X}
  734. X
  735. X/*
  736. X*******************************************************************************
  737. X* Public_function_declarations.
  738. X*******************************************************************************
  739. X*/
  740. X/*
  741. X    -- Register Object Class
  742. X*******************************************************************************
  743. X    This procedure adds object class name to our list of registered
  744. X    classes/constructors. So far very simplistic ... without checking for 
  745. X    duplicate entries, no cache hashing scheme....no ties to app_context.
  746. X*/
  747. Xvoid WsRegisterObjectClass ( app, name, class )
  748. XXtAppContext    app;        /* not used (yet), must be present      */
  749. XString          name;        /* constructor name, case insensitive   */
  750. XWidgetClass     class;      /* Xt object class pointer              */
  751. X{
  752. X    char           cr_name[MAX_XRMSTRING];
  753. X    register char *s;
  754. X    register char *d;
  755. X
  756. X    for ( d=cr_name, s=name; *s; s++)
  757. X         *d++ = (isupper(*s)) ? tolower (*s) : *s;
  758. X    *d = '\0';
  759. X
  760. X    if (classes_num >= classes_max )
  761. X    {
  762. X    classes_max += ADD_CLASSES;
  763. X    classes_ptr  = (ClCacheRec*) XtRealloc((char*)classes_ptr, 
  764. X                             sizeof(ClCacheRec) * classes_max);
  765. X    }
  766. X    classes_ptr[classes_num].quark       = XrmStringToQuark ( cr_name );
  767. X    classes_ptr[classes_num].constructor = NULL;
  768. X    classes_ptr[classes_num].class       = class;
  769. X    classes_num++;
  770. X}
  771. X
  772. X/*
  773. X    -- Register constructor
  774. X*******************************************************************************
  775. X    This procedure adds constructor procedure/name to our list of registered
  776. X    classes/constructors. So far very simplistic ... without checking for 
  777. X    duplicate entries, no cache hashing scheme....no ties to app_context.
  778. X
  779. X    Note the constructor is a "standard" widget creation routine
  780. X     Widget WsCreateXyyyZyyy ( parent, name, args, nargs )
  781. X*/
  782. Xvoid WsRegisterConstructor ( app, name, constructor )
  783. XXtAppContext    app;        /* not used (yet), must be present      */
  784. XString          name;        /* constructor name, case insensitive   */
  785. XWidget (*constructor) ();   /* pointer to a widget creation routine */
  786. X{
  787. X    char           cr_name[MAX_XRMSTRING];
  788. X    register char *s;
  789. X    register char *d;
  790. X
  791. X    for ( d=cr_name, s=name; *s; s++)
  792. X         *d++ = (isupper(*s)) ? tolower (*s) : *s;
  793. X    *d = '\0';
  794. X
  795. X    if (classes_num >= classes_max )
  796. X    {
  797. X    classes_max += ADD_CLASSES;
  798. X    classes_ptr  = (ClCacheRec*) XtRealloc((char*)classes_ptr, 
  799. X                             sizeof(ClCacheRec) * classes_max);
  800. X    }
  801. X    classes_ptr[classes_num].quark       = XrmStringToQuark ( cr_name );
  802. X    classes_ptr[classes_num].constructor = constructor;
  803. X    classes_ptr[classes_num].class       = NULL;
  804. X    classes_num++;
  805. X}
  806. X
  807. X/*
  808. X    -- Create Xrm Database Children
  809. X*******************************************************************************
  810. X    This routine creates widget children as defined in X reosurce databse.
  811. X    We look for children defintion starting at child 0 (first looking
  812. X    for managed, then unmanaged child). The child lookup terminates if
  813. X    child_0 is not present, or two two subsequent child lookups failed 
  814. X    (allowing to continue if one child was defined incorrectly).
  815. X    
  816. X    To reduce the databse search overhead, we only attempt to create
  817. X    children for composite widgets and objects.
  818. X*/
  819. Xvoid WsCreateXrmChildren ( w )
  820. XWidget w;
  821. X{
  822. X    Widget     child;
  823. X    Widget     prev;
  824. X    Widget     managed[MAX_CHILDREN];
  825. X    register int i,num;
  826. X
  827. X/*  -- check if the requested widget is a manager ( composite ) */
  828. X    if (! ( XtIsSubclass( w, compositeWidgetClass ) 
  829. X         || XtIsSubclass( w, compositeObjectClass ) /* not in R3 intrinsics */
  830. X     ) ) return;    
  831. X    
  832. X
  833. X/*  -- look for children definition until we have 2 subsequent misses */
  834. X    child = (Widget) 1;
  835. X    prev  = (Widget) 0;        /* this makes the child_0 mandatory */
  836. X
  837. X    for ( i=0, num=0; (prev || child) ;i++)
  838. X    {
  839. X    child   = CreateDatabaseChild ( w, i, "managed" );
  840. X    if ( child )
  841. X      managed[num++] = child;
  842. X    else
  843. X      child = CreateDatabaseChild ( w, i, "unmanaged" );
  844. X     prev = child;
  845. X    }
  846. X    XtManageChildren(managed, num );
  847. X}
  848. X
  849. X
  850. X/*
  851. X    -- Create Xrm Children callback
  852. X*******************************************************************************
  853. X
  854. X    For each widget specified by the list of widget names in client data,
  855. X    (or the widget invoking this callback if client data is NULL), this
  856. X    callback creates any children defined in the Xrm database:
  857. X
  858. X    ....widget.managed.child_0:   name,constr_name[,n[onrecursive]]
  859. X    ....widget.unmanaged.child_0: name,constr_name[,n[onrecursive]]
  860. X
  861. X    If resource above (child_0 - child_nn) exists, the callback creates
  862. X    (and optionally manages) a child using a constructor routine registered
  863. X    under "constr_name".
  864. X    The creation process recursivly follows the widget tree, unless
  865. X    the constructor is specified with the "nonrecursive" option, or
  866. X    a non-composite widget/object is found.
  867. X
  868. X    The search for "child_n" resource stops if two subsequent children
  869. X    or child_0 are not specified, or their creation fails (error).
  870. X
  871. X    After all children have been created, the string of widget names
  872. X    is changed to an empty one ("\0"), to prevent duplicate widget
  873. X    creation.
  874. X
  875. X*/
  876. Xvoid WsCreateXrmChildrenCB ( w,  client, call )
  877. XWidget w;
  878. Xcaddr_t client;        /* client data, list of named children */
  879. Xcaddr_t call;        /* call data,   not used */
  880. X{
  881. X    Widget*    widget_list[MAX_CHILDREN];
  882. X    Cardinal    widget_count;
  883. X    int        i;
  884. X
  885. X
  886. X    /* for NULL client, we get back "w", for "\0" we get zero widget count */
  887. X    NamesToWidgetList ( w, client, widget_list, &widget_count );
  888. X
  889. X    for ( i=0; i<widget_count; i++)
  890. X        WsCreateXrmChildren(widget_list[i]);
  891. X
  892. X    /* prevent repeated invokation by changing string to empty "\0" one */
  893. X    if ( client )
  894. X        *client = NUL;    
  895. X}
  896. X
  897. X/*
  898. X    -- Manage named children callback
  899. X*******************************************************************************
  900. X    This callback translates string passed in as client data into a widget id
  901. X    and manages it. A comma separated list of children can be specified.
  902. X    NULL string pointer defaults widget invoking the callback
  903. X*/
  904. Xvoid WsManageNamedChildrenCB ( w,  client, call )
  905. XWidget w;
  906. Xcaddr_t client;        /* client data, list of named children */
  907. Xcaddr_t call;        /* call data,   not used */
  908. X{
  909. X    Widget*    widget_list[MAX_CHILDREN];
  910. X    Cardinal    widget_count;
  911. X
  912. X    NamesToWidgetList ( w, client, widget_list, &widget_count );
  913. X    XtManageChildren  ( widget_list, widget_count );
  914. X}
  915. X
  916. X
  917. X/*
  918. X    -- Unmanage named children callback
  919. X*******************************************************************************
  920. X    This callback translates string passed in as client data into a widget id
  921. X    and manages it. A comma separated list of children can be specified.
  922. X    NULL string pointer defaults widget invoking the callback
  923. X*/
  924. Xvoid WsUnmanageNamedChildrenCB ( w,  client, call )
  925. XWidget w;
  926. Xcaddr_t client;        /* client data, list of named children */
  927. Xcaddr_t call;        /* call data,   not used */
  928. X{
  929. X    Widget*    widget_list[MAX_CHILDREN];
  930. X    Cardinal    widget_count;
  931. X
  932. X    NamesToWidgetList ( w, client, widget_list, &widget_count );
  933. X    XtUnmanageChildren  ( widget_list, widget_count );
  934. X}
  935. X
  936. X
  937. X/*
  938. X    -- Set Widget Resource Callback
  939. X*******************************************************************************
  940. X    This callback loads invoking widget into the prescribed resource of the
  941. X    named widget(s).
  942. X    Typically, this callback is used to set the "XmNdefaultButton" resource,
  943. X    and is invoked from button creation callback.
  944. X
  945. X    The client data argument has a format:
  946. X        
  947. X    resource_name,target_widget_name[,target_widget_name...]
  948. X*/
  949. Xvoid WsSetWidgetResourceCB ( w,  client, call )
  950. XWidget w;
  951. Xcaddr_t client;        /* client data, resource name, list of named children */
  952. Xcaddr_t call;        /* call data,   not used */
  953. X{
  954. X    Widget*       widget_list[MAX_CHILDREN];
  955. X    Cardinal       widget_count;
  956. X    char       resource[MAX_XRMSTRING];
  957. X    register char *d,*s;
  958. X    register int   i;
  959. X    Arg            args[1];
  960. X
  961. X    for ( d=resource, s=client; (*s && *s!=','); s++ )
  962. X        if (*s > ' ') *d++ = *s;
  963. X    *d = NUL;
  964. X
  965. X    if (*s == ',' ) s++;
  966. X    if (*s == NUL )
  967. X    {
  968. X    XtWarning("No widget names for WsSetWidgetresourceCB");
  969. X    return;
  970. X    }
  971. X    NamesToWidgetList ( w, s, widget_list, &widget_count );
  972. X
  973. X    /* set the resource to set */
  974. X    args[0].name  = resource;
  975. X    args[0].value = (XtArgVal)w;
  976. X
  977. X    for (i=0; i<widget_count; i++)    
  978. X    XtSetValues ( widget_list[i], args, 1 );
  979. X}
  980. X
  981. X/*
  982. X    -- Load Resource File
  983. X*******************************************************************************
  984. X    This callbacks loads the specified resource file into application
  985. X    resource database. It allows to load the resources on as-needed
  986. X    basis, reducing the intitial resource load overhead.
  987. X    
  988. X    Two locations are searched for a specified file:
  989. X
  990. X    XAPP_DEFAULT_PATH     
  991. X    XUSER_DEFAULT_PATH (or env.variable "XAPPLRESLANGPATH")
  992. X
  993. X    Not implemented -- too toolkit dependent ( R3/Motif/R4 ).
  994. X*/
  995. Xvoid WsLoadResourceFileCB ( w,  client, call )
  996. XWidget w;
  997. Xcaddr_t client;        /* client data, X resources file name */
  998. Xcaddr_t call;        /* call data,   not used */
  999. X{
  1000. X    printf("Sorry, deffered resource load not implemented, file %s\n",call);
  1001. X    printf("Merge your file into application class file\n");
  1002. X}
  1003. X
  1004. X/*
  1005. X  -- WsRegisterXrmCallbacks
  1006. X*******************************************************************************
  1007. X*/
  1008. Xvoid WsRegisterXrmCallbacks ( app )
  1009. XXtAppContext app;
  1010. X{
  1011. X#define REG( name, cb, cl ) WsRegisterCallback ( app, name, cb, cl )
  1012. X
  1013. X    REG("CreateXrmChildrenCB",      WsCreateXrmChildrenCB,    NULL );
  1014. X    REG("ManageNamedChildrenCB",    WsManageNamedChildrenCB,    NULL );
  1015. X    REG("UnmanageNamedChildrenCB",  WsUnmanageNamedChildrenCB,    NULL );
  1016. X    REG("SetWidgetResourceCB",      WsSetWidgetResourceCB,    NULL );
  1017. X
  1018. X#undef REG
  1019. X}
  1020. END_OF_FILE
  1021. if test 22340 -ne `wc -c <'WsCreateXrmFunc.c'`; then
  1022.     echo shar: \"'WsCreateXrmFunc.c'\" unpacked with wrong size!
  1023. fi
  1024. # end of 'WsCreateXrmFunc.c'
  1025. fi
  1026. if test -f 'WsCvtStrToCallback.c' -a "${1}" != "-c" ; then 
  1027.   echo shar: Will not clobber existing file \"'WsCvtStrToCallback.c'\"
  1028. else
  1029. echo shar: Extracting \"'WsCvtStrToCallback.c'\" \(10320 characters\)
  1030. sed "s/^X//" >'WsCvtStrToCallback.c' <<'END_OF_FILE'
  1031. X/*
  1032. X*******************************************************************************
  1033. X*
  1034. X* SCCS_data: %Z%%M% %I%(%G%)
  1035. X*
  1036. X* Module_name:
  1037. X*
  1038. X*     WsCvtStrToCallback
  1039. X*
  1040. X* Subsystem_group:
  1041. X*
  1042. X*     Window System, Widget Set, Converters
  1043. X*
  1044. X* Related_keywords: 
  1045. X*
  1046. X*     Converter
  1047. X*
  1048. X* Module_description:
  1049. X*
  1050. X*     This module contains the String To Callback X resource converter.
  1051. X*
  1052. X*     The converter parses the resource string in the format:
  1053. X*
  1054. X*       ...path:   name[(args)][,name[(args)]]...
  1055. X*
  1056. X*     where:  name:   specifies the registered callback function name
  1057. X*             args:   specifies the string passed to a callback as
  1058. X*              "client data".
  1059. X*
  1060. X*     Multiple callbacks can be specified for a single callback list
  1061. X*     resource.  Any callbacks must be "registered" by the application
  1062. X*     prior converter invocation (.i.e.prior widget creation).
  1063. X*     If no "args" string is provided, the default "client data" 
  1064. X*     specified at callback registration are used.
  1065. X*
  1066. X* Module_interface_summary: 
  1067. X*
  1068. X*
  1069. X*     Resource converter is invoked indirectly by the toolkit. The
  1070. X*     converter is added to the toolkit by widgets calling
  1071. X*     WsAddStrToCallbackP() in the widget intialization code.
  1072. X*
  1073. X*     To register application callbacks, use:
  1074. X*
  1075. X*     WsRegisterCallback ( 
  1076. X*        WsAppContext    app,    - application context
  1077. X*        String        name,    - register name, case insensitive
  1078. X*        Callback        callback,    - callback function pointer
  1079. X*        ClientData      closure )    - default client data
  1080. X*
  1081. X* Module_history:
  1082. X*                                                  
  1083. X*   mm/dd/yy  initials  function  action
  1084. X*   --------  --------  --------  ---------------------------------------------
  1085. X*   02/26/90  MarBru    All       Created
  1086. X*
  1087. X* Design_notes:
  1088. X*
  1089. X*   For VMS, we could have used LIB$FIND_IMAGE_SYMBOL and use dynamic
  1090. X*   (runtime) binding. But since most UNIX systems lack such capability,
  1091. X*   we stick to the concept of "registration" routines.
  1092. X*
  1093. X*******************************************************************************
  1094. X*/
  1095. X/*
  1096. X*******************************************************************************
  1097. X* Include_files.
  1098. X*******************************************************************************
  1099. X*/
  1100. X
  1101. X/*  -- Operating system includes */
  1102. X#include <strings.h>
  1103. X#include <ctype.h>
  1104. X
  1105. X/*  -- X Window System includes */
  1106. X#include <X11/IntrinsicP.h>
  1107. X#include <X11/StringDefs.h> 
  1108. X
  1109. X/*  -- Auto-trol Window System includes */
  1110. X
  1111. X/*
  1112. X*******************************************************************************
  1113. X* Private_constant_declarations.
  1114. X*******************************************************************************
  1115. X*/
  1116. X#undef  NUL
  1117. X#define NUL '\0'
  1118. X
  1119. X/*
  1120. X*******************************************************************************
  1121. X* Private_type_declarations.
  1122. X*******************************************************************************
  1123. X*/
  1124. X#define MAX_XRMSTRING  1024        /* max length of the DB string        */
  1125. X#define MAX_CALLBACKS    64        /* max number of callbacks per list */
  1126. X#define ADD_CALLBACKS     16             /* increment of callback cache size */
  1127. X
  1128. X/*
  1129. X*******************************************************************************
  1130. X* Private_macro_definitions.
  1131. X*******************************************************************************
  1132. X*/
  1133. X
  1134. X/*
  1135. X*******************************************************************************
  1136. X* Private_data_definitions.
  1137. X*******************************************************************************
  1138. X    The following cache/registry of known callbacks, initially empty, 
  1139. X    is loaded by the application using "registration" routines.
  1140. X    Assuming small numbers of callbacks, the sequential search
  1141. X    of such cache is (initially) considered acceptable.
  1142. X*/
  1143. X
  1144. X/*  -- Named callback procedures cache, intially empty */
  1145. X
  1146. Xtypedef struct
  1147. X{
  1148. X    XrmQuark       quark;        /* quarkified callback name   */
  1149. X    XtCallbackProc callback;        /* callback procedure pointer */
  1150. X    caddr_t        closure;             /* default client data        */
  1151. X} CBCacheRec;
  1152. X
  1153. X
  1154. X
  1155. Xstatic int       callbacks_num = 0;
  1156. Xstatic int       callbacks_max = 0;
  1157. Xstatic CBCacheRec *callbacks_ptr = NULL;
  1158. X
  1159. X
  1160. X/*
  1161. X*******************************************************************************
  1162. X* Private_function_declarations.
  1163. X*******************************************************************************
  1164. X*/
  1165. X
  1166. X/*
  1167. X    -- Convert String To Callback
  1168. X*******************************************************************************
  1169. X    This conversion creates a callback list structure from the X resource
  1170. X    database string in format:
  1171. X
  1172. X    name(arg),name(arg).....
  1173. X
  1174. X    Note "name" is not case sensitive, while "arg" may be - it is passed to
  1175. X    a callback as client data as a null terminated string (first level
  1176. X    parenthesis stripped off).
  1177. X*/
  1178. Xvoid CvtStringToCallback (args, num_args, fromVal, toVal)
  1179. X
  1180. XXrmValue *args;
  1181. XCardinal *num_args;
  1182. XXrmValue *fromVal;
  1183. XXrmValue *toVal;
  1184. X{
  1185. X    typedef struct 
  1186. X    {
  1187. X    char *nsta,*nend;        /* callback name start, end */
  1188. X    char *asta,*aend;        /* argument string start, end */
  1189. X    } Segment;
  1190. X
  1191. X    static XtCallbackRec *cb;
  1192. X    XtCallbackRec      callback_list[MAX_CALLBACKS];
  1193. X    int                   callback_num = 0;
  1194. X    String                string = (char *) fromVal->addr;
  1195. X    Segment               segs[MAX_CALLBACKS];    
  1196. X    Segment              *seg;
  1197. X    register char        *s;
  1198. X    register int          i,ipar;
  1199. X
  1200. X/*  -- assume error or undefined input argument */
  1201. X    toVal->size = 0;
  1202. X    toVal->addr = (caddr_t) NULL;
  1203. X    if (s == NULL) return;
  1204. X
  1205. X/*  -- parse input string finding segments   "name(arg)" comma separated */
  1206. X    ipar = 0;
  1207. X    seg  = segs;
  1208. X    seg->nsta = string;
  1209. X    seg->nend = seg->asta = seg->aend = (char*)NULL;
  1210. X
  1211. X    for ( s=string;  *s;  s++ )
  1212. X    {
  1213. X    switch (*s)
  1214. X    {
  1215. X    case ',':  if ( ipar > 0 ) break;  /* commas in arguments ignored  */
  1216. X           if ( seg->nend == NULL ) seg->nend = s-1;  /* no argument */
  1217. X               seg++;           /* start the next segment */
  1218. X               seg->nsta = (s[1]) ? s+1 : (char*)NULL;
  1219. X               seg->nend = seg->asta = seg->aend = (char*)NULL;
  1220. X           break;           
  1221. X
  1222. X    case '(':  if ( ipar++ == 0 ) { seg->nend = s-1; seg->asta = s+1; };
  1223. X               break;
  1224. X           
  1225. X    case ')':  if ( --ipar == 0 ) { seg->aend = s-1; };
  1226. X           break;
  1227. X    deafult:   ;
  1228. X    }
  1229. X    }
  1230. X    seg++;           /* start the terminating segment */
  1231. X    seg->nsta = (char*)NULL;
  1232. X
  1233. X    if (ipar)
  1234. X    {
  1235. X    XtStringConversionWarning (string, "Callback, unbalanced parenthesis");
  1236. X    return;
  1237. X    }
  1238. X
  1239. X
  1240. X/*  -- process individual callback string segments "name(arg)" */
  1241. X    for( seg = segs;  seg->nsta;   seg++)
  1242. X    {
  1243. X        char                 cb_name[MAX_XRMSTRING];
  1244. X    XtCallbackProc       found = (XtCallbackProc)NULL;
  1245. X    XrmQuark             quark;
  1246. X    register char    *d;
  1247. X    register char    *end;
  1248. X
  1249. X    /* our callback cache names are case insensitive, no white space */
  1250. X    for ( s=seg->nsta, d=cb_name; s<=seg->nend; )
  1251. X       if ( *s > ' ')
  1252. X             *d++ = (isupper(*s) ) ? tolower (*s++) : *s++;
  1253. X       else
  1254. X          s++;
  1255. X    *d   = NUL;
  1256. X
  1257. X        /* try to locate callback in our cache of callbacks */
  1258. X        quark = XrmStringToQuark (cb_name);
  1259. X    for (i=0; i<callbacks_num; i++)
  1260. X        if ( callbacks_ptr[i].quark == quark )
  1261. X        {
  1262. X            register XtCallbackRec *rec = &callback_list[callback_num];
  1263. X        rec->callback = found = callbacks_ptr[i].callback;
  1264. X            rec->closure  = callbacks_ptr[i].closure;
  1265. X        break;
  1266. X        }
  1267. X
  1268. X    /* we have found a registered callback, process arguments */
  1269. X    if (found)
  1270. X    {
  1271. X       register char *arg;
  1272. X       register int   alen;
  1273. X       register XtCallbackRec *rec = &callback_list[callback_num];
  1274. X       
  1275. X       if ( seg->asta )
  1276. X       {
  1277. X           alen = (int)seg->aend - (int)seg->asta +1;
  1278. X           arg  = XtMalloc(alen+1);
  1279. X           strncpy ( arg, seg->asta, alen );
  1280. X           arg[alen+1]  = NUL;
  1281. X           rec->closure = (caddr_t)arg;
  1282. X       }
  1283. X       callback_num++;
  1284. X        }
  1285. X    else
  1286. X    {
  1287. X           XtStringConversionWarning (cb_name, "Callback, unknown callback name");
  1288. X    }
  1289. X    } /* end for seg loop */
  1290. X
  1291. X/*  -- terminate the callback list */
  1292. X    {
  1293. X    register XtCallbackRec *rec = &callback_list[callback_num];
  1294. X        rec->callback = NULL;
  1295. X    rec->closure  = NULL;
  1296. X    callback_num++;
  1297. X    }
  1298. X
  1299. X/*  -- make a permanent copy of the new callback list, and return a pointer */
  1300. X    cb = (XtCallbackRec*)XtMalloc( callback_num * sizeof (XtCallbackRec) );
  1301. X    memcpy ( (char*)cb, (char*)callback_list,  
  1302. X              callback_num * sizeof (XtCallbackRec));
  1303. X    toVal->size = sizeof (XtCallbackRec*);
  1304. X    toVal->addr = (caddr_t)&cb;
  1305. X}
  1306. X
  1307. X/*
  1308. X*******************************************************************************
  1309. X* Public_function_declarations.
  1310. X*******************************************************************************
  1311. X*/
  1312. X
  1313. X/*
  1314. X    -- Add String To Callback Convertor
  1315. X*******************************************************************************
  1316. X*/
  1317. X
  1318. Xvoid WsAddStringToCallbackP ()
  1319. X{
  1320. X    static Boolean added = FALSE;
  1321. X    if ( !added )
  1322. X    {
  1323. X       XtAddConverter    (XtRString, 
  1324. X                          XtRCallback,
  1325. X                          CvtStringToCallback,
  1326. X                          (XtConvertArgList)NULL,
  1327. X                          (Cardinal)0);
  1328. X       added = TRUE;
  1329. X    }
  1330. X}
  1331. X
  1332. X
  1333. X/*
  1334. X    -- Register callback
  1335. X*******************************************************************************
  1336. X    This procedure adds callback procedure/name to our list of registered
  1337. X    callbacks. So far very simplistic ... without checking for duplicate
  1338. X    entries, no cache hashing scheme, no ties to app_context.
  1339. X*/
  1340. Xvoid WsRegisterCallback ( app, name, callback, closure )
  1341. XXtAppContext    app;        /* not used (yet), must be present      */
  1342. XString          name;       /* callback name, case insensitive      */
  1343. XXtCallbackProc  callback;   /* callback function pointer            */
  1344. Xcaddr_t         closure;    /* default closure (client data)        */
  1345. X{
  1346. X    char           cb_name[MAX_XRMSTRING];
  1347. X    register char *s;
  1348. X    register char *d;
  1349. X
  1350. X    for ( d=cb_name, s=name; *s; s++)
  1351. X         *d++ = (isupper(*s)) ? tolower (*s) : *s;
  1352. X    *d = '\0';
  1353. X
  1354. X    if (callbacks_num >= callbacks_max )
  1355. X    {
  1356. X    callbacks_max += ADD_CALLBACKS;
  1357. X    callbacks_ptr  = (CBCacheRec*) XtRealloc((char*)callbacks_ptr, 
  1358. X                      sizeof(CBCacheRec) * callbacks_max);
  1359. X    }
  1360. X    callbacks_ptr[callbacks_num].quark    = XrmStringToQuark ( cb_name );
  1361. X    callbacks_ptr[callbacks_num].callback = callback;
  1362. X    callbacks_ptr[callbacks_num].closure  = closure;
  1363. X    callbacks_num++;
  1364. X}
  1365. END_OF_FILE
  1366. if test 10320 -ne `wc -c <'WsCvtStrToCallback.c'`; then
  1367.     echo shar: \"'WsCvtStrToCallback.c'\" unpacked with wrong size!
  1368. fi
  1369. # end of 'WsCvtStrToCallback.c'
  1370. fi
  1371. if test -f 'HelloWorld.c' -a "${1}" != "-c" ; then 
  1372.   echo shar: Will not clobber existing file \"'HelloWorld.c'\"
  1373. else
  1374. echo shar: Extracting \"'HelloWorld.c'\" \(3743 characters\)
  1375. sed "s/^X//" >'HelloWorld.c' <<'END_OF_FILE'
  1376. X/*
  1377. X*******************************************************************************
  1378. X*   HelloWorld.c 
  1379. X*******************************************************************************
  1380. X    This program demonstrates usage of the Xrm (X resource management) databse
  1381. X    for a widget tree definition and management.
  1382. X    There is very little code in this example, since the entire user interface
  1383. X    definition is stored in the Xrm database, preferably in the application
  1384. X    class resource file:  ~/HelloWorld
  1385. X
  1386. X    ATTC NOTE: This example does NOT use Ws, since it's intended for use
  1387. X           outside Auto-trol.
  1388. X/*
  1389. X*******************************************************************************
  1390. X*   Include_files.
  1391. X*******************************************************************************
  1392. X*/
  1393. X
  1394. X#include <Xm/Xm.h>        /* Motif public header file    */
  1395. X#include <Xm/Label.h>        /* Motif label widget        */
  1396. X#include <Xm/PushB.h>        /* Motif pushbutton widget    */
  1397. X#include <Xm/BulletinB.h>    /* Motif bulletin board widget    */
  1398. X#include <Xm/RowColumn.h>    /* Motif row column widget    */
  1399. X#include "WsCreateXrm.h"    /* Window System Xrm Creation routines */
  1400. X
  1401. X/*
  1402. X*******************************************************************************
  1403. X*   Application callback declaration (callbacks should be in a separate file)
  1404. X*******************************************************************************
  1405. X*/
  1406. Xvoid pushCB();
  1407. X
  1408. X/* 
  1409. X*******************************************************************************
  1410. X*   MAIN function
  1411. X*******************************************************************************
  1412. X*/
  1413. X
  1414. Xmain ( argc, argv )
  1415. Xint    argc;
  1416. Xchar **argv;
  1417. X{   
  1418. X    Widget       app_shellW;          /* application shell widget       */
  1419. X    XtAppContext app;
  1420. X
  1421. X/*  -- Intialize AWS creating the application shell */
  1422. X    app_shellW = XtInitialize ( "helloWorld","HelloWorld",
  1423. X                 NULL, 0, &argc, argv );
  1424. X    app        = XtWidgetToApplicationContext(app_shellW);
  1425. X
  1426. X/*  -- Register the string to callback converter, used for a pushbutton */
  1427. X    WsAddStringToCallbackP();
  1428. X
  1429. X/*  -- Register available Widget constructors */
  1430. X    WsRegisterConstructor ( app, "xmLabel",        XmCreateLabel     );
  1431. X    WsRegisterConstructor ( app, "xmPushButton",    XmCreatePushButton);
  1432. X    WsRegisterConstructor ( app, "xmRowColumn",        XmCreateRowColumn );
  1433. X    WsRegisterObjectClass ( app, "xmBulletinBoard", xmBulletinBoardWidgetClass);
  1434. X
  1435. X/*  -- Register available callbacks */
  1436. X    WsRegisterXrmCallbacks( app );
  1437. X    WsRegisterCallback    ( app, "push",  pushCB, NULL );
  1438. X
  1439. X
  1440. X/*  -- Create children of the toplevel shell defined by the Xrm database */
  1441. X    WsCreateXrmChildren   ( app_shellW );
  1442. X
  1443. X/*  -- Realize the widget tree and enter the main application loop */
  1444. X    XtRealizeWidget  ( app_shellW );
  1445. X    XtMainLoop       ( );
  1446. X}
  1447. X/*
  1448. X*******************************************************************************
  1449. X    Application callbacks (should be in a separate file)
  1450. X*******************************************************************************
  1451. X*/
  1452. X/*
  1453. X    -- Push callback
  1454. X*******************************************************************************
  1455. X    This callback is a state machine; the first invocation loads the text
  1456. X    specified as client data into XmNlabelString resource of invoking widget;
  1457. X    the next invocation exits the application.
  1458. X*/
  1459. Xvoid   pushCB ( w, client, call )
  1460. XWidget        w;
  1461. Xcaddr_t        client;
  1462. Xcaddr_t        call;
  1463. X{
  1464. X    static Boolean first = TRUE;
  1465. X    
  1466. X    if ( first )
  1467. X    {
  1468. X        static Arg setargs[] = { XmNlabelString, NULL };
  1469. X    String  text = ( client ) ? (String) client : "No text in Xrdb" ;
  1470. X
  1471. X        setargs[0].value = (XtArgVal)XmStringCreateLtoR(text,XmSTRING_DEFAULT_CHARSET);
  1472. X    WsSetResources ( w, setargs, 1);
  1473. X    first = FALSE;
  1474. X    }
  1475. X    else
  1476. X    {
  1477. X    exit();
  1478. X    }    
  1479. X}
  1480. END_OF_FILE
  1481. if test 3743 -ne `wc -c <'HelloWorld.c'`; then
  1482.     echo shar: \"'HelloWorld.c'\" unpacked with wrong size!
  1483. fi
  1484. # end of 'HelloWorld.c'
  1485. fi
  1486. if test -f 'HelloWorld_Basic' -a "${1}" != "-c" ; then 
  1487.   echo shar: Will not clobber existing file \"'HelloWorld_Basic'\"
  1488. else
  1489. echo shar: Extracting \"'HelloWorld_Basic'\" \(851 characters\)
  1490. sed "s/^X//" >'HelloWorld_Basic' <<'END_OF_FILE'
  1491. X#  HelloWorld - global resources
  1492. X#
  1493. X*fontList:             -*-Helvetica-Medium-R-Normal--14*
  1494. X#  
  1495. X#  shell
  1496. X#
  1497. XHelloWorld.managed.child_0:          box,xmRowColumn
  1498. X#
  1499. X#  box - the main container
  1500. X#
  1501. XHelloWorld.box.spacing:            2    
  1502. XHelloWorld.box.background:           red
  1503. XHelloWorld.box.marginWidth:        4
  1504. XHelloWorld.box.marginHeight:        4    
  1505. XHelloWorld.box.entryAlignment:        alignment_center
  1506. XHelloWorld.box.managed.child_0:      label,xmlabel 
  1507. XHelloWorld.box.managed.child_1:         button,xmpushbutton
  1508. X#
  1509. X#  label
  1510. X#
  1511. XHelloWorld.box.label.background:    white
  1512. XHelloWorld.box.label.foreground:    blue
  1513. XHelloWorld.box.label.labelString:    Hello, WORLD !
  1514. X#
  1515. X#  button
  1516. X#
  1517. XHelloWorld.box.button.background:    lightBlue
  1518. XHelloWorld.box.button.foreground:    white
  1519. XHelloWorld.box.button.location:         center
  1520. XHelloWorld.box.button.labelString:    Push ME
  1521. XHelloWorld.box.button.activateCallback: push(Push to EXIT)
  1522. X#
  1523. END_OF_FILE
  1524. if test 851 -ne `wc -c <'HelloWorld_Basic'`; then
  1525.     echo shar: \"'HelloWorld_Basic'\" unpacked with wrong size!
  1526. fi
  1527. # end of 'HelloWorld_Basic'
  1528. fi
  1529. if test -f 'HelloWorld_More' -a "${1}" != "-c" ; then 
  1530.   echo shar: Will not clobber existing file \"'HelloWorld_More'\"
  1531. else
  1532. echo shar: Extracting \"'HelloWorld_More'\" \(2171 characters\)
  1533. sed "s/^X//" >'HelloWorld_More' <<'END_OF_FILE'
  1534. X#
  1535. X#  HelloWorld 
  1536. X#    box        main container
  1537. X#       lbl1        headline label - hello world
  1538. X#       box1        bulletin board for default button testing
  1539. X#          btn1        default button
  1540. X#       btn2            button controlling lbl2
  1541. X#       btn3            button controlling lbl2
  1542. X#       lbl2            footnote
  1543. X#
  1544. X#  global resources
  1545. X#
  1546. X*fontList:                    -*-Helvetica-Medium-R-Normal--14*
  1547. X#
  1548. X#  shell 
  1549. X#
  1550. XHelloworld.input:            true
  1551. XHelloWorld.managed.child_0:          box,xmRowColumn
  1552. X#
  1553. X#  box - the main container
  1554. X#
  1555. XHelloWorld.box.layout:           column
  1556. XHelloWorld.box.spacing:            8
  1557. XHelloWorld.box.background:           red
  1558. XHelloWorld.box.marginWidth:        0
  1559. XHelloWorld.box.marginHeight:        0
  1560. XHelloWorld.box.entryAlignment:        alignment_center
  1561. XHelloWorld.box.managed.child_0:      lbl1,xmLabel 
  1562. XHelloWorld.box.managed.child_1:         box1,xmBulletinBoard
  1563. XHelloWorld.box.managed.child_2:         btn2,xmPushButton
  1564. XHelloWorld.box.managed.child_3:         btn3,xmPushButton
  1565. XHelloWorld.box.managed.child_4:      lbl2,xmLabel 
  1566. X#
  1567. X#  lbl1
  1568. X#
  1569. XHelloWorld.box.lbl1.background:        white
  1570. XHelloWorld.box.lbl1.foreground:        blue
  1571. XHelloWorld.box.lbl1.labelString:    Hello, WORLD !
  1572. X#
  1573. X#  box1
  1574. X#
  1575. XHelloWorld.box.box1.marginWidth:    8
  1576. XHelloWorld.box.box1.marginHeight:    8
  1577. XHelloWorld.box.box1.managed.child_0:    btn1,xmPushButton
  1578. X#
  1579. X#  btn1
  1580. X#
  1581. XHelloWorld.box.box1.btn1.labelString:    Push ME
  1582. XHelloWorld.box.box1.btn1.background:    lightBlue
  1583. XHelloWorld.box.box1.btn1.foreground:    red
  1584. XHelloWorld.box.box1.btn1.showAsDefault: 2
  1585. XHelloWorld.box.box1.btn1.xrmCreateCallback: SetWidgetResourceCB(defaultButton,box.box1)
  1586. XHelloWorld.box.box1.btn1.activateCallback:  push(Push to EXIT !)
  1587. X#
  1588. X#  btn2
  1589. X#
  1590. XHelloWorld.box.btn2.background:        lightBlue
  1591. XHelloWorld.box.btn2.foreground:        blue
  1592. XHelloWorld.box.btn2.labelString:    Remove Footnote
  1593. XHelloWorld.box.btn2.activateCallback:     UnmanageNamedChildrenCB(box.lbl2)
  1594. X#
  1595. X#  btn3
  1596. X#
  1597. XHelloWorld.box.btn3.background:        lightBlue
  1598. XHelloWorld.box.btn3.foreground:        blue
  1599. XHelloWorld.box.btn3.labelString:    Add Footnote
  1600. XHelloWorld.box.btn3.activateCallback:     ManageNamedChildrenCB(box.lbl2)
  1601. X#
  1602. X#  lbl2
  1603. X#
  1604. XHelloWorld.box.lbl2.background:        white
  1605. XHelloWorld.box.lbl2.foreground:        blue
  1606. XHelloWorld.box.lbl2.labelString:    Ain't it WONDERFULL ?
  1607. X#
  1608. END_OF_FILE
  1609. if test 2171 -ne `wc -c <'HelloWorld_More'`; then
  1610.     echo shar: \"'HelloWorld_More'\" unpacked with wrong size!
  1611. fi
  1612. # end of 'HelloWorld_More'
  1613. fi
  1614. echo shar: End of shell archive.
  1615. exit 0
  1616.  
  1617. dan
  1618. -----------------------------------------------------------
  1619.             O'Reilly && Associates
  1620.         argv@sun.com / argv@ora.com
  1621.        632 Petaluma Ave, Sebastopol, CA 95472 
  1622.      800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104
  1623.     Opinions expressed reflect those of the author only.
  1624.